home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / COMMUNIC / 1572B.ZIP / KMT_IBM4.ZIP / MSSCMD.ASM next >
Assembly Source File  |  1989-07-11  |  64KB  |  1,268 lines

  1.         NAME    msscmd
  2. ; File MSSCMD.ASM
  3. ; Edit history:
  4. ; Last edit 21 Nov 1988
  5. ; 21 Nov 1988 Version 2.32
  6. ; 17 Oct 1988 Make command keyword search failure yield global kstatus of
  7. ;  failure status, to inform Take/Macros of a defective command.
  8. ; 4 Aug 1988 Fix keyword count initialization in help display.
  9. ; 1 July 1988 Version 2.31
  10. ; 7 June 1988 Add comand.impdo flag to permit a keyword search failure to
  11. ;  retry as a DO cmd (macro table). Used only by main Kermit command level.
  12. ; 27 May 1988 Allow "-<cr>" as line continuation pair and let "\-<cr>"
  13. ;  stand for "-<end of line>". Add comand.cmblen to sense buffer overflow on
  14. ;  calls to cmtxt; if comand.cmblen is left at zero then use 128 byte limit
  15. ;  (comand.cmblen is cleared at command end).
  16. ; 15 May 1988 Make :label keywords no-ops, make query ordinary char in TAKEs.
  17. ; 6 May 1988 Show ambiguous keywords at parse time, do graceful interaction.
  18. ; 28 March 1988 Permit '\%x' (x = '0' or above) in commands as 'variables'
  19. ;  (substituted string of text). Words are obtained from Macro table mcctab.
  20. ;  DEF MAC and DO MAC define variables. DEF macro uses comand.cmper > 0 to
  21. ;  allow '\%x'to be stored as a literal. Variables work in any command except
  22. ;  DEF MAC. Major redesign of whole parser. [jrd]
  23. ; 4 March 1988 Rewrite keyword parsing to permit non-alphabetized tables
  24. ;  and 8-bit characters. Add byte comand.cmwhite which when non-zero permits
  25. ;  leading whitespace in cmtxt and cmfile commands; it is reset at command
  26. ;  completion. Move procedure Prompt here from mssker. [jrd]
  27. ; 27 Feb 1988 Add capability of stdin being a file. [jrd]
  28. ; 1 Jan 1988 version 2.30
  29.  
  30.         public comnd, comand, prserr
  31.         public intake, isdev, iseof, prompt, tolowr
  32.         include mssdef.h
  33.  
  34. datas   segment public 'datas'
  35.         extrn   flags:byte, trans:byte, taklev:byte, takadr:word, mcctab:byte
  36.         extrn   kstatus:byte
  37.  
  38. comand  cmdinfo <>
  39. cmer00  db      cr,lf,'?Program internal error, recovering$'
  40. cmer01  db      cr,lf,'?More parameters are needed$'
  41. cmer02  db      cr,lf,'?Word "$'
  42. cmer03  db      '" is not usable here$'
  43. cmer04  db      '" is ambiguous$'
  44. cmer07  db      cr,lf,'?Ignoring extra characters "$'
  45. cmer08  db      '"$'
  46. cmer09  db      cr,lf,'?Text exceeded available buffer capacity$'
  47. cmin00  db      ' Confirm with carriage return$'
  48. cmin01  db      ' One of the following:',cr,lf,'$'
  49. stkmsg  db      cr,lf,bell,'?Exhausted work space! Circular definition?$'
  50. crlf    db      cr,lf,'$'
  51. ctcmsg  db      5eh,'C$'
  52. temp    dw      0                       ; temp (counts char/line so far)
  53. errflag db      0                       ; non-zero to suppress cmcfrm errors
  54. kwstat  db      0                       ; get-keyword status
  55. cmdstk  dw      0                       ; stack pointer at comand call time
  56. intake  db      0                       ; last command line was from Take
  57. prevch  db      0                       ; previous char read by cmgetc
  58. noparse db      0                       ; semicolons not special, if non-zero
  59. subcnt  db      0                       ; count of chars matched in '\%'
  60. datas   ends
  61.  
  62. code    segment public 'code'
  63.         extrn   ctlu:near, cmblnk:near, clearl:near, locate:near, takrd:near
  64.         extrn   takclos:near, docom:near
  65.         assume  cs:code, ds:datas, es:nothing
  66.  
  67. ;       This routine parses the specified function in AH. Any additional
  68. ;       information is in DX and BX.
  69. ;       Returns rskp on success and ret on failure
  70.  
  71. COMND   PROC NEAR
  72.         mov     cmdstk,sp               ; save stack ptr for longjmp exit
  73.         mov     noparse,0               ; recognize semicolons in Take files
  74.         cmp     ah,cmcfm                ; Parse a confirm?
  75.         jne     cm2                     ; nz = no
  76.         jmp     cmcfrm                  ; get a confirm
  77. cm2:    cmp     ah,cmkey                ; Parse a keyword?
  78.         jne     cm3
  79.         jmp     cmkeyw                  ; Try and get one
  80. cm3:    cmp     ah,cmtxt                ; Parse arbitrary text
  81.         jne     cm4
  82.         jmp     cmtext
  83. cm4:    cmp     ah,cmfile               ; parse text surrounded by whitespace
  84.         jne     cm5
  85.         jmp     cmfil0
  86. cm5:    mov     ah,prstr                ; Else give error
  87.         mov     dx,offset cmer00        ; "?Program internal error"
  88.         int     dos
  89.         jmp     prserr
  90. COMND   ENDP
  91.  
  92. ; This routine parses a keyword from the table pointed at by DX, help text
  93. ; point to by BX. Format of the table is as follows (use macro mkeyw):
  94. ;       addr:   db      N         ; Where N is the # of entries in the table
  95. ;               db      M         ; M is the size of the keyword (excl '$')
  96. ;               db      'string$' ; String is the keyword
  97. ;               dw      value     ; Value is data to be returned
  98. ; Keywords may be in any order and in mixed case.
  99. ; Return is rskp for success and ret for failure.
  100.  
  101. ; comand.cmptab: pointer to keyword table (supplied by caller)
  102. ; comand.cmhlp: pointer to help message (supplied by caller)
  103. ; comand.cmsptr: pointer to current user word text
  104. ; comand.cmsiz: length of user text, excluding terminator
  105. ; comand.cmcr: 0 = empty lines not allowed, 1 = empty lines allowed
  106. ; comand.cmwhite: non-zero allows leading whitespace for cmtxt and cmfile,
  107. ;                 reset automatically at end of call
  108. ; comand.cmwptr: buffer write pointer to next free byte
  109. ; comand.cmrptr: buffer read pointer for next free byte
  110. ; comand.cmper: 0 to do \%x substitution. Set to 0 at end of call
  111. ; comand.impdo: non-zero permits keyword failure to retry as DO command, reset
  112. ;                automatically at time of failure.
  113. cmkeyw  proc    near
  114.         mov     comand.cmsiz,0          ; user word length
  115.         mov     ax,comand.cmrptr        ; get command reading pointer
  116.         mov     comand.cmsptr,ax        ; set pointer for start of user word
  117.         mov     comand.cmhlp,bx         ; save the help pointer
  118.         mov     comand.cmptab,dx        ; save the beginning of keyword table
  119.         mov     bx,dx
  120.         cmp     byte ptr[bx],0          ; get number of entries in table
  121.         jne     cmky1
  122.         jmp     cmky7                   ; e = no keywords to check, error
  123. cmky1:  mov     comand.cmsflg,0ffh      ; skip leading spaces/tabs
  124.         call    cmgtch                  ; get char from the user into ah
  125.         jc      cmky3                   ; c = terminator
  126.         mov     dx,comand.cmrptr        ; next byte to read
  127.         dec     dx                      ; where we just read a char
  128.         mov     comand.cmsptr,dx        ; remember start of keyword
  129.         inc     comand.cmsiz            ; start counting user chars
  130. cmky2:  call    cmgtch                  ; read until terminator
  131.         jc      cmky3                   ; c = terminator
  132.         inc     comand.cmsiz            ; count user chars
  133.         jmp     short cmky2             ; no terminator yet
  134.  
  135. cmky3:  cmp     ah,'?'                  ; need help?
  136.         jne     cmky4                   ; ne = no
  137.         jmp     cmkyhlp                 ; do help and exit
  138. cmky4:  cmp     ah,escape               ; escape?
  139.         jne     cmky6                   ; ne = no
  140.         call    cmkyesc                 ; process escape
  141.         jc      cmky5                   ; c = failure (no unique keyword yet)
  142.         mov     comand.cmper,0          ; reset to variable recognition
  143.         mov     comand.cmkeep,0
  144.         mov     comand.impdo,0          ; clear flag to prevent loops
  145.         mov     comand.cmquiet,0        ; permit echoing again
  146.         jmp     rskp                    ; return successfully to user
  147.  
  148. cmky5:  cmp     comand.cmsiz,0          ; started a word yet?
  149.         je      cmky1                   ; e = no, ignore escape, keep looking
  150.         jmp     cmkyhlp                 ; ne = yes, show type of error
  151.  
  152. cmky6:  cmp     comand.cmsiz,0          ; length of user's text, empty?
  153.         je      cmky7                   ; e = yes, parse error
  154.         push    bx
  155.         mov     bx,comand.cmsptr        ; point at first user character
  156.         cmp     byte ptr[bx],':'        ; start of a label?
  157.         pop     bx
  158.         jne     cmky6a                  ; ne = no, return success
  159.         mov     comand.cmsiz,1          ; say just one byte
  160. cmky6a:
  161.         call    getkw                   ; get unique kw, point to it with bx
  162.         jc      cmky8                   ; c = not found
  163.         add     bl,[bx]                 ; add length of keyword text (CNT)
  164.         adc     bh,0
  165.         add     bx,2                    ; point at value field
  166.         mov     bx,[bx]                 ; bx = return value following keyword
  167.         mov     comand.cmper,0          ; reset to variable recognition
  168.         mov     comand.cmkeep,0
  169.         mov     comand.impdo,0          ; clear flag to prevent loops
  170.         mov     comand.cmquiet,0        ; permit echoing again
  171.         mov     errflag,0
  172.         jmp     rskp                    ; return successfully
  173.                                         ; all other terminators come here
  174. cmky7:  cmp     comand.cmsiz,0          ; empty table or empty user's text?
  175.         jne     cmky8                   ; ne = no
  176.         cmp     comand.cmcr,0           ; empty lines allowed?
  177.         jne     cmky10                  ; ne = yes, do not complain
  178.         push    dx
  179.         mov     ah,prstr
  180.         mov     dx,offset cmer01        ; command word expected
  181.         int     dos
  182.         pop     dx
  183.         mov     comand.cmquiet,0        ; permit echoing again
  184.         mov     comand.impdo,0          ; clear flag to prevent loops
  185.         ret                             ; do ret exit
  186.  
  187. cmky8:  cmp     comand.impdo,0          ; failed here, ok to try Macro table?
  188.         je      cmky8a                  ; e = no, use regular exit path
  189.         mov     comand.impdo,0          ; yes, but clear flag to prevent loops
  190.         mov     comand.cmrptr,offset comand.cmdbuf ; reinit read pointer
  191.         mov     comand.cmquiet,1        ; suppress echoing of same keyword
  192.         mov     bx,offset docom         ; return DO as "found" keyword
  193.         jmp     rskp                    ; return success to invoke DO
  194.  
  195. cmky8a: mov     comand.cmquiet,0        ; permit echoing again
  196.         mov     errflag,1               ; say already doing error recovery
  197.         or      kstatus,1               ; global command status, failure
  198.         call    isdev                   ; reading pretyped lines?
  199.         jnc     cmky9                   ; nc = yes, consume rest of line
  200.         cmp     taklev,0                ; in a Take file?
  201.         jne     cmky9                   ; ne = yes
  202.         call    cmskw                   ; display offending keyword
  203.         dec     comand.cmrptr           ; interactive, backup to terminator
  204.         mov     bx,comand.cmrptr        ; look at it
  205.         cmp     byte ptr [bx],' '       ; got here on space terminator?
  206.         jne     cmky10                  ; ne = no, (cr,lf,ff) exit failure
  207.         mov     ah,prstr                ; start a fresh line
  208.         mov     dx,offset crlf
  209.         int     dos
  210.         call    bufreset                ; cut back buffer to just before term
  211.         jmp     repars                  ; reparse interactive lines
  212.  
  213. cmky9:  call    cmcfrm                  ; get formal end of command line
  214.          nop                            ;  to maintain illusion of typeahead
  215.          nop                            ;  and let user backspace to correct
  216.          nop                            ;  mistakes (we reparse everything)
  217.         call    cmskw                   ; display offending keyword
  218. cmky10: ret                             ; do ret exit
  219. cmkeyw  endp
  220.  
  221. ;;;;;; start support routines for keyword parsing.
  222.  
  223. cmkyesc proc    near                    ; deal with escape terminator
  224.         call    bufreset                ; reset buffer to end just before ESC
  225.         cmp     comand.cmsiz,0          ; user word length, empty?
  226.         jne     cmkye2                  ; ne = have user text, else complain
  227. cmkye1: call    esceoc                  ; do normal escape end-of-command
  228.         stc                             ; say failure to fill out word
  229.         ret
  230.                                         ; add unique keyword to buffer
  231. cmkye2: call    getkw                   ; is there a matching keyword?
  232.         jc      cmkye1                  ; c = ambiguous or not found
  233.         push    bx                      ; unique, bx points to structure
  234.         push    si
  235.         mov     cl,[bx]                 ; length of keyword
  236.         mov     ch,0
  237.         inc     bx                      ; point to first letter
  238.         mov     si,comand.cmwptr        ; where next char goes
  239.         mov     dx,comand.cmsiz         ; length of user word
  240.         add     bx,dx                   ; add chars known so far
  241.         sub     cx,dx                   ; calculate number yet to add
  242.         add     comand.cmsiz,cx
  243.         jcxz    cmkye4                  ; z = none
  244.         mov     ah,conout               ; display new char
  245. cmkye3: mov     al,[bx]                 ; get a keyword letter
  246.         inc     bx
  247.         call    tolowr                  ; lowercase
  248.         mov     [si],al                 ; store it
  249.         inc     si
  250.         mov     dl,al
  251.         int     dos                     ; display it
  252.         loop    cmkye3                  ; do all new chars
  253. cmkye4: mov     byte ptr[si],' '        ; insert space terminator in buffer
  254.         mov     dl,' '                  ; display it
  255.         mov     ah,conout
  256.         int     dos
  257.         inc     si
  258.         mov     comand.cmrptr,si        ; move token pointer after the space
  259.         mov     comand.cmwptr,si        ; next free slot is after the space
  260.         mov     comand.cmsflg,0ffh      ; set space-seen flag
  261.         pop     si
  262.         pop     bx                      ; bx = keyword structure
  263.         add     bl,[bx]                 ; add length of keyword text
  264.         adc     bh,0
  265.         add     bx,2                    ; point at value field
  266.         mov     bx,[bx]                 ; bx = return value following keyword
  267.         clc                             ; carry clear for success
  268.         ret
  269. cmkyesc endp
  270.  
  271. esceoc  proc    near                    ; do normal escape end-of-command
  272.         push    ax
  273.         push    dx
  274.         mov     ah,conout               ; ring the bell
  275.         mov     dl,bell
  276.         int     dos
  277.         pop     dx
  278.         pop     ax
  279.         call    bufreset                ; reset buffer
  280.         stc                             ; say error condition
  281.         ret
  282. esceoc  endp
  283.  
  284. ; Help. Question mark entered by user.  Display all the keywords that match
  285. ; user text. If text is null then use external help if available; otherwise,
  286. ; display all keywords in the table. Removes question mark from buffer and
  287. ; invokes reparse of command line to-date. User word starts at .cmsptr and
  288. ; is .cmsiz bytes long.
  289. cmkyhlp proc    near
  290.         mov     cx,0                    ; clear number of keyword (none yet)
  291.         cmp     comand.cmsiz,0          ; user text given?
  292.         jne     cmkyh1                  ; ne = yes, use matching keywords
  293.         cmp     comand.cmhlp,0          ; external help given?
  294.         jne     cmkyh6                  ; yes, use it instead of full table
  295. cmkyh1: mov     temp,0                  ; count # chars printed on this line
  296.         mov     bx,comand.cmptab        ; beginning of kw table
  297.         mov     ch,[bx]                 ; length of table
  298.         mov     cl,0                    ; no keywords or help displayed yet
  299.         inc     bx                      ; point at CNT field
  300. cmkyh2: cmp     comand.cmsiz,0          ; length of user word
  301.         je      cmkyh3                  ; e = null, use full table
  302.         call    cmpwrd                  ; compare keyword with user word
  303.         jc      cmkyh5                  ; c = no match, get another keyword
  304. cmkyh3: mov     al,[bx]                 ; length of table keyword
  305.         add     byte ptr temp,al        ; count chars printed so far
  306.         cmp     temp,76                 ; will this take us beyond column 78?
  307.         jbe     cmkyh4                  ; be = no, line has more room
  308.         mov     ah,prstr
  309.         mov     dx,offset crlf          ; break the line
  310.         int     dos
  311.         mov     temp,0                  ; and reset the count
  312. cmkyh4: cmp     cl,0                    ; any keywords found yet?
  313.         jne     cmkyh4a                 ; ne = yes
  314.         mov     dx,offset cmin01        ; start with One of the following: msg
  315.         mov     ah,prstr
  316.         int     dos
  317.         inc     cl                      ; say one keyword has been found
  318. cmkyh4a:mov     dl,spc                  ; put two spaces before each keyword
  319.         mov     ah,conout
  320.         int     dos
  321.         int     dos
  322.         add     temp,2                  ; count output chars
  323.         mov     dx,bx                   ; get current keyword structure
  324.         inc     dx                      ;  text part
  325.         mov     ah,prstr
  326.         int     dos                     ; display it
  327. cmkyh5: dec     ch                      ; are we at end of table?
  328.         jle     cmkyh7                  ; le = yes, quit now
  329.         add     bl,[bx]                 ; next keyword, add CNT chars to bx
  330.         adc     bh,0
  331.         add     bx,4                    ; skip CNT, '$' and 16 bit value
  332.         jmp     cmkyh2                  ; go examine this keyword
  333.  
  334. cmkyh6: mov     dx,comand.cmhlp         ; external help text
  335.         mov     ah,prstr
  336.         int     dos
  337.         inc     cl                      ; say gave help already
  338. cmkyh7: cmp     cl,0                    ; found any keywords?
  339.         jne     cmkyh9                  ; ne = yes
  340.         mov     cx,comand.cmsiz         ; length of word
  341.         cmp     cx,0
  342.         jg      cmkyh8                  ; g = something to show
  343.         push    dx
  344.         mov     ah,prstr
  345.         mov     dx,offset cmer01        ; command word expected
  346.         int     dos
  347.         pop     dx
  348.         jmp     prserr
  349. cmkyh8: mov     kwstat,0                ; set keyword not-found status
  350.         call    cmskw                   ; display offending keyword
  351. cmkyh9: mov     ah,prstr                ; start a fresh line
  352.         mov     dx,offset crlf
  353.         int     dos
  354.         call    bufreset                ; cut back buffer to just before '?'
  355.         jmp     repars
  356. cmkyhlp endp
  357.  
  358. ; See if keyword is ambiguous or not from what the user has typed in.
  359. ; Return carry set if word is ambiguous or not found, carry clear otherwise.
  360. ; Uses table pointed at by comand.cmptab, user text pointed at by
  361. ; comand.cmsptr and length in comand.cmsiz.
  362. cmambg  proc    near
  363.         push    bx
  364.         push    cx
  365.         push    dx
  366.         mov     dl,0                    ; count keyword matches so far
  367.         mov     bx,comand.cmptab        ; look at start of keyword table
  368.         mov     cl,[bx]                 ; get number of entries in table
  369.         mov     ch,0                    ; use cx as a counter
  370.         jcxz    cmamb8                  ; z = no table so always ambiguous
  371.         inc     bx                      ; look at CNT byte of keyword
  372. cmamb4: call    cmpwrd                  ; user vs table words, same?
  373.         jc      cmamb6                  ; c = no match
  374.         inc     dl                      ; count this as a match
  375.         cmp     dl,1                    ; more than one match?
  376.         ja      cmamb8                  ; a = yes, quit now
  377. cmamb6: add     bl,[bx]                 ; add CNT chars to bx
  378.         adc     bh,0
  379.         add     bx,4                    ; skip CNT, '$' and 16 bit value
  380.         loop    cmamb4                  ; do rest of keyword table
  381. cmamb7: cmp     dl,1                    ; how many matches were found?
  382.         jne     cmamb8                  ; ne = none or more than 1: ambiguous
  383.         pop     dx                      ; restore main registers
  384.         pop     cx
  385.         pop     bx
  386.         clc
  387.         ret                             ; ret = not ambiguous
  388. cmamb8: pop     dx                      ; restore main registers
  389.         pop     cx
  390.         pop     bx
  391.         stc
  392.         ret                             ; return ambiguous or not found
  393. cmambg  endp
  394.  
  395. ; Compare user text with keyword, abbreviations are considered a match.
  396. ; Enter with bx pointing at keyword table CNT field for a keyword.
  397. ; Return carry clear if they match, set if they do not match. User text
  398. ; pointed at by comand.cmsptr and length is in comand.cmsiz.
  399. ; Registers preserved.
  400.  
  401. cmpwrd  proc    near
  402.         push    cx
  403.         mov     cx,comand.cmsiz         ; length of user's text
  404.         jcxz    cmpwrd2                 ; z: null user word matches no keyword
  405.         cmp     cl,[bx]                 ; user's text longer than keyword?
  406.         ja      cmpwrd2                 ; a = yes, no match
  407.         push    ax
  408.         push    bx
  409.         push    si
  410.         inc     bx                      ; point at table's keyword text
  411.         mov     si,comand.cmsptr        ; buffer ptr to user input
  412.         cld
  413. cmpwrd1:lodsb                           ; user text
  414.         mov     ah,[bx]                 ; keyword text
  415.         inc     bx                      ; next keyword letter
  416.         call    tolowr                  ; force lower case on both chars
  417.         cmp     ah,al                   ; same?
  418.         loope   cmpwrd1                 ; e = same so far
  419.         pop     si
  420.         pop     bx
  421.         pop     ax
  422.         jne     cmpwrd2                 ; ne = mismatch
  423.         pop     cx                      ; recover keyword counter
  424.         clc                             ; they match
  425.         ret
  426. cmpwrd2:pop     cx                      ; recover keyword counter
  427.         stc                             ; they do not match
  428.         ret
  429. cmpwrd  endp
  430.  
  431. ; Get pointer to keyword structure using user text. Uses keyword table
  432. ; pointed at by comand.cmptab and comand.cmsiz holding length
  433. ; of user's keyword (cmpwrd needs comand.cmsptr pointing at user's
  434. ; keyword and length of comand.cmsiz). Structure pointer returned in BX.
  435. ; Return carry clear for success and carry set for failure. Modifies BX.
  436. getkw   proc    near
  437.         push    cx
  438.         mov     kwstat,0                ; keyword status, set to not-found
  439.         cmp     comand.cmsiz,0          ; length of user word, empty?
  440.         je      getkw3                  ; e = yes, fail
  441.         mov     bx,comand.cmptab        ; table of keywords
  442.         mov     cl,[bx]                 ; number of keywords in table
  443.         mov     ch,0
  444.         jcxz    getkw3                  ; z = none, fail
  445.         inc     bx                      ; point to first
  446. getkw1: call    cmpwrd                  ; compare user vs table words
  447.         jc      getkw2                  ; c = failed to match word, try next
  448.         mov     kwstat,1                ; say found one keyword, maybe more
  449.         push    dx
  450.         mov     dx,comand.cmsiz         ; users word length
  451.         cmp     [bx],dl                 ; same length (end of keyword)?
  452.         pop     dx
  453.         je      getkw4                  ; e = yes, exact match. Done
  454.         call    cmambg                  ; ambiguous?
  455.         jnc     getkw4                  ; nc = unique, done, return with bx
  456.         mov     kwstat,2                ; say more than one such keyword
  457. getkw2: add     bl,[bx]                 ; next keyword, add CNT chars to bx
  458.         adc     bh,0
  459.         add     bx,4                    ; skip CNT, '$' and 16 bit value
  460.         loop    getkw1                  ; do all, exhaustion = failure
  461. getkw3: pop     cx
  462.         stc                             ; return failure
  463.         ret
  464. getkw4: pop     cx
  465.         clc                             ; return success
  466.         ret
  467. getkw   endp
  468.  
  469. ; show offending keyword message. Comand.cmsptr points to user word,
  470. ; comand.cmsiz has length. Modifies AX, CX, and DX.
  471. cmskw   proc    near
  472.         mov     ah,prstr                ; not one of the above terminators
  473.         mov     dx,offset cmer02        ; '?Word "'
  474.         int     dos
  475.         mov     cx,comand.cmsiz         ; length of word
  476.         jcxz    cmskw3                  ; z = null
  477.         mov     ah,conout
  478.         push    si
  479.         mov     si,comand.cmsptr        ; point to word
  480.         cld
  481. cmskw1: lodsb
  482.         cmp     al,' '                  ; control code?
  483.         jae     cmskw2                  ; ae = no
  484.         push    ax
  485.         mov     dl,5eh                  ; caret
  486.         int     dos
  487.         pop     ax
  488.         add     al,'A'-1                ; plus ascii bias
  489. cmskw2: mov     dl,al                   ; display chars in word
  490.         int     dos
  491.         loop    cmskw1
  492.         pop     si
  493. cmskw3: mov     dx,offset cmer03        ; '" not usable here.'
  494.         cmp     kwstat,1                ; kywd status from getkw, not found?
  495.         jb      cmskw4                  ; b = not found, a = ambiguous
  496.         mov     dx,offset cmer04        ; '" ambiguous'
  497. cmskw4: mov     ah,prstr
  498.         int     dos
  499.         ret
  500. cmskw   endp
  501. ;;;;;;;;;; end of support routines for keyword parsing.
  502.  
  503. ; Parse arbitrary text up to a CR. Enter with BX = pointer to output buffer,
  504. ; DX pointing to help text. Produces asciiz string. Return updated pointer in
  505. ; BX and output size in AH. Leading spaces are omitted unless comand.cmwhite
  506. ; is non-zero (cleared upon exit). It does not need to be followed by the
  507. ; usual call to confirm the line. Byte comand.cmblen can be used to specify
  508. ; the length of the caller's buffer; cleared to zero by this command to
  509. ; imply a length of 127 bytes (default) and if zero at startup use 127 bytes.
  510. cmtext  proc    near
  511.         mov     comand.cmptab,bx        ; save pointer to data buffer
  512.         mov     comand.cmhlp,dx         ; save the help message
  513.         mov     cx,0                    ; init the char count
  514.         cmp     comand.cmblen,0         ; length of user's buffer given?
  515.         jne     cmtxt0                  ; ne = yes
  516.         mov     comand.cmblen,127       ; else set 127 byte limit plus null
  517. cmtxt0: mov     comand.cmsflg,0ffh      ; skip initial spaces
  518.         cmp     comand.cmwhite,0        ; allow leading whitespace?
  519.         je      cmtxt1a                 ; e = no
  520. cmtxt1: mov     comand.cmsflg,0         ; get all spaces
  521. cmtxt1a:call    cmgtch                  ; get a char
  522.         jnc     cmtxt5                  ; nc = non-terminator, put in buffer
  523.         cmp     ah,' '                  ; space?
  524.         je      cmtxt5                  ; e = yes, record it
  525.         cmp     ah,escape               ; escape?
  526.         jne     cmtxt2                  ; ne = no
  527.         call    esceoc                  ; do normal escape end-of-command
  528.         jmp     cmtxt0                  ; try again
  529.  
  530. cmtxt2: cmp     ah,'?'                  ; asking a question?
  531.         je      cmtxt3                  ; e = yes
  532.         cmp     ah,cr                   ; formal carriage return?
  533.         je      cmtxt2a                 ; e = yes
  534.         inc     comand.cmrptr           ; accept char into buffer
  535.         jmp     cmtxt5                  ;  and record the char
  536. cmtxt2a:mov     ah,cl                   ; return count in AH
  537.         mov     bx,comand.cmptab        ; return updated pointer
  538.         mov     byte ptr[bx],0          ; put terminator into the buffer
  539.         mov     comand.cmwhite,0        ; clear leading whitespace flag
  540.         mov     comand.cmper,0          ; reset to variable recognition
  541.         mov     comand.cmblen,0         ; set user buffer length to unknown
  542.         mov     comand.cmkeep,0
  543.         jmp     rskp
  544.                                         ; Help processor
  545. cmtxt3: inc     comand.cmrptr           ; count the ?
  546.         cmp     cx,0                    ; Is "?" first char?
  547.         jne     cmtxt5                  ; ne = no, just add to buffer
  548.         dec     comand.cmrptr
  549.         mov     comand.cmsiz,0          ; no keyword for help
  550.         mov     comand.cmwhite,0        ; clear leading whitespace flag
  551.         cmp     comand.cmhlp,0          ; external help given?
  552.         jne     cmtxt3a                 ; ne = yes
  553.         mov     comand.cmhlp,offset cmin00 ; confirm with c/r msg
  554.         mov     comand.cmblen,0         ; set user buf length to unknown
  555. cmtxt3a:jmp     cmkyhlp                 ; do help process
  556.  
  557. cmtxt5: inc     cx                      ; increment the count
  558.         mov     bx,comand.cmptab        ; pointer into destination array
  559.         mov     [bx],ah                 ; put char into the buffer
  560.         inc     bx
  561.         mov     al,0
  562.         mov     [bx],al                 ; insert null terminator
  563.         mov     comand.cmptab,bx
  564.         cmp     ch,0                    ; overflowed into high byte?
  565.         jne     cmtxt6                  ; ne = yes
  566.         cmp     cl,comand.cmblen        ; buffer filled?
  567.         ja      cmtxt6                  ; a = yes, declare error
  568.         jb      cmtxt5a                 ; a = not filled yet
  569.         mov     ah,conout               ; notify user that the buffer is full
  570.         mov     dl,bell
  571.         int     dos
  572. cmtxt5a:jmp     cmtxt1
  573. cmtxt6: mov     ah,prstr
  574.         mov     dx,offset cmer09
  575.         int     dos
  576.         jmp     prserr                  ; declare parse error
  577. cmtext  endp
  578.  
  579.  
  580. ; Parse arbitrary text up to whitespace.  Enter with DX pointing to output
  581. ; buffer and BX pointing to help text. Produces asciiz string. Return updated
  582. ; pointer in DX and input size in AH. Skips leading whitespace unless
  583. ; comand.cmwhite is non-zero (cleared upon exit). Does a return skip exit.
  584.  
  585. cmfil0  proc    near
  586.         mov     comand.cmptab,dx        ; save pointer to data buffer
  587.         mov     comand.cmhlp,bx         ; save the help message
  588.         mov     comand.cmsiz,0          ; init the char count
  589. cmfil0a:cmp     comand.cmwhite,0        ; allow leading whitespace?
  590.         jne     cmfil1                  ; ne = yes
  591.         mov     comand.cmsflg,0ffh      ; omit leading space
  592. cmfil1: call    cmgtch                  ; get a char
  593.         jc      cmfi1a                  ; c = terminator
  594.         jmp     cmfil5                  ; put char into the buffer
  595. cmfi1a: cmp     ah,escape               ; escape?
  596.         je      cmfi1b                  ; e = yes
  597.         jmp     cmfil2                  ; process other terminators
  598.  
  599. cmfi1b: call    esceoc                  ; do normal escape end-of-command
  600.         jmp     cmfil0a                 ; try again
  601. cmfil2: cmp     ah,'?'                  ; asking a question?
  602.         je      cmfil3                  ; e = yes
  603.         xchg    dx,bx                   ; re-interchange bx and dx
  604.         mov     comand.cmwhite,0        ; clear whitespace flag
  605.         mov     comand.cmper,0          ; reset to variable recognition
  606.         mov     comand.cmkeep,0
  607.         mov     bx,comand.cmptab        ; pointer into destination array
  608.         mov     byte ptr[bx],0          ; put null terminator into the buffer
  609.         inc     bx
  610.         mov     ah,byte ptr comand.cmsiz ; return count in AH
  611.         mov     dx,comand.cmptab        ; return updated pointer
  612.         xchg    dx,bx                   ; re-interchange bx and dx
  613.         mov     comand.cmwhite,0        ; clear whitespace flag
  614.         mov     comand.cmper,0          ; reset to variable recognition
  615.         mov     comand.cmkeep,0
  616.         jmp     rskp                    ; return success
  617.  
  618. cmfil3: inc     comand.cmrptr           ; count the ?
  619.         cmp     comand.cmsiz,0          ; Is "?" first char?
  620.         jne     cmfil5                  ; ne = no, just add to buffer
  621.         dec     comand.cmrptr
  622.         mov     comand.cmsiz,0
  623.         cmp     comand.cmhlp,0          ; external help given?
  624.         jne     cmfil3a                 ; ne = yes
  625.         mov     comand.cmhlp,offset cmin00 ; confirm with c/r msg
  626. cmfil3a:jmp     cmkyhlp                 ; do help process
  627.  
  628. cmfil5: inc     comand.cmsiz            ; inrement the count
  629.         mov     bx,comand.cmptab        ; pointer into destination array
  630.         mov     [bx],ah                 ; put char into the buffer
  631.         inc     bx
  632.         mov     comand.cmptab,bx
  633.         jmp     cmfil1                  ; the end of cmfil0
  634. cmfil0  endp
  635.  
  636. ; This routine gets a confirm (CR) and displays any extra non-blank text.
  637. ; errflag non-zero means suppress "extra text" display in this routine
  638. ; because another routine is handling errors.
  639. cmcfrm  proc    near
  640.         mov     comand.cmper,1          ; do not react to \%x substitutions
  641. cmcfr1: mov     comand.cmsflg,0ffh      ; set space-seen flag (skip spaces)
  642.         call    cmgtch                  ; get a char
  643.         push    comand.cmrptr
  644.         pop     temp                    ; remember first non-space position
  645.         jc      cmcfr4                  ; c = terminator
  646.         dec     temp                    ; backup to text char
  647. cmcfr3: mov     comand.cmsflg,0ffh      ; set space-seen flag (skip spaces)
  648.         call    cmgtch
  649.         jnc     cmcfr3                  ; read until terminator
  650. cmcfr4: cmp     ah,' '
  651.         je      cmcfr3                  ; ignore ending on space
  652.         cmp     ah,escape               ; escape?
  653.         jne     cmcfr5                  ; ne = no
  654.         call    esceoc                  ; do standard end of cmd on escape
  655.         mov     ax,comand.cmrptr
  656.         cmp     ax,temp                 ; started text yet?
  657.         je      cmcfr1                  ; e = no
  658.         jmp     short cmcfr3            ; try again
  659. cmcfr5: cmp     ah,'?'                  ; curious?
  660.         jne     cmcfr6                  ; ne = no
  661.         mov     comand.cmhlp,offset cmin00 ; msg Confirm with c/r
  662.         mov     comand.cmsiz,0          ; no keyword
  663.         mov     errflag,0
  664.         jmp     cmkyhlp                 ; do help
  665. cmcfr6: cmp     ah,cr                   ; the confirmation char?
  666.         jne     cmcfr3                  ; ne = no
  667.         cmp     errflag,0               ; already doing one error?
  668.         jne     cmcfr7                  ; ne = yes, skip this one
  669.         mov     cx,comand.cmrptr        ; pointer to terminator
  670.         mov     dx,temp                 ; starting place
  671.         sub     cx,dx                   ; end minus starting point = length
  672.         cmp     cx,0                    ; string present?
  673.         jle     cmcfr7                  ; le = nothing to display
  674.         push    dx                      ; save source pointer
  675.         mov     ah,prstr
  676.         mov     dx,offset cmer07        ; ?Ignoring extras
  677.         int     dos
  678.         pop     dx
  679.         mov     bx,1                    ; stdout handle, cx=count, dx=src ptr
  680.         mov     ah,write2               ; allow embedded dollar signs
  681.         int     dos
  682.         mov     ah,prstr
  683.         mov     dx,offset cmer08        ; trailer msg
  684.         int     dos
  685. cmcfr7: mov     errflag,0
  686.         mov     comand.cmper,0          ; reset to variable recognition
  687.         mov     comand.cmkeep,0
  688.         jmp     rskp                    ; return confirmed
  689. cmcfrm  endp
  690.  
  691. ;;; Routines to get and edit incoming text.
  692.  
  693. ; Detect '\%x' (x = '0' or above) and substitute the matching Macro string
  694. ; in place of the '\%x' phrase in the user's buffer. If comand.cmper != 0
  695. ; then treat '\%' as literal characters. If no matching parameter exists
  696. ; just remove '\%x'. Returns carry clear if nothing done, else carry set and
  697. ; new text already placed in user's buffer. comand.cmwptr and comand.cmcnt
  698. ; are updated. Uses depth-first recursion algorithm. All registers preserved.
  699. subst   proc    near
  700.         cmp     comand.cmper,0          ; should we recognize '\%'?
  701.         jne     subst2                  ; ne = no, treat as literals
  702.         cmp     ah,'\'                  ; is it the first char of the pattern?
  703.         jne     subst1                  ; ne = no, try next
  704.         mov     subcnt,1                ; say first is matched
  705.         jmp     short subst2            ; exit successfully
  706. subst1: cmp     subcnt,1                ; first char matched already?
  707.         ja      subst3                  ; a = first two have been matched
  708.         jb      subst2                  ; b = none yet
  709.         inc     subcnt                  ; assume a match follows
  710.         cmp     ah,'%'                  ; second match char, same?
  711.         je      subst2                  ; e = yes
  712.         mov     subcnt,0                ; mismatch, clear match counter
  713. subst2: clc                             ; carry clear = no substitution done
  714.         ret
  715. subst3: mov     subcnt,0                ; clear match counter
  716.         cmp     ah,'0'                  ; third char is '0' or above?
  717.         jb      subst2                  ; b = out of range, no match
  718.         push    bx                      ; save working regs
  719.         push    cx
  720.         sub     comand.cmrptr,3         ; reread commands where backslash was
  721.         call    bufreset                ; reset buffer to this point
  722.         push    comand.cmptab           ; save current keyword parsing parms
  723.         push    comand.cmsptr
  724.         push    comand.cmsiz
  725.         mov     bx,comand.cmrptr        ; points at backslash
  726.         mov     comand.cmsptr,bx        ; direct keyword routine to it
  727.         mov     comand.cmsiz,3          ; three bytes (\%x) of user text
  728.         mov     comand.cmptab,offset mcctab ; use Macro table for new text
  729.         call    getkw                   ; get ptr, bx, to matching keyword
  730.         pop     comand.cmsiz            ; restore borrowed keyword parameters
  731.         pop     comand.cmsptr
  732.         pop     comand.cmptab
  733.         jc      substx                  ; c = not found, keep after pops
  734.         mov     cl,byte ptr[bx]         ; length of found word
  735.         add     cl,2                    ; plus count field and '$'
  736.         mov     ch,0
  737.         add     bx,cx                   ; point to 16 bit value (string ptr)
  738.         mov     bx,[bx]                 ; point to string structure
  739.         mov     cl,[bx]                 ; length of string (ch=0 from above)
  740.         inc     bx                      ; skip length byte, bx=string address
  741.         jcxz    substx                  ; z = nothing left to transfer
  742.         cld
  743. subst4: mov     ah,[bx]                 ; get a char
  744.         inc     bx
  745.         push    di                      ; assume di is used by other routines
  746.         mov     di,comand.cmrptr
  747.         mov     [di],ah                 ; store char (without es:di)
  748.         inc     di
  749.         mov     comand.cmwptr,di        ; where to store next char
  750.         mov     comand.cmrptr,di        ; move read pointer too
  751.         cmp     di,offset comand.cmdbuf+size cmdbuf ; reached max buffer size?
  752.         pop     di
  753.         jae     subst6                  ; ae = yes, no more room
  754.         cmp     sp,20*2                 ; still some stack space?
  755.         jle     subst6                  ; le = insufficient room
  756.         call    SUBST                   ; rescan what we stored (recursion)
  757.         jnc     subst5                  ; nc = no substitution, so no kbd test
  758.         push    ax                      ; break out of loops with Control-C
  759.         push    dx
  760.         mov     ah,constat              ; check console status for Control-C
  761.         int     dos                     ;  our control-break handler sees it
  762.         pop     dx                      ;  and cmgetc reads it
  763.         pop     ax
  764. subst5: loop    subst4
  765. substx: pop     cx
  766.         pop     bx
  767.         stc                             ; set carry to say have stored chars
  768.         ret
  769. subst6: mov     ah,prstr
  770.         mov     dx,offset stkmsg        ; out of work space msg
  771.         int     dos
  772.         jmp     prserr                  ; and declare parse error
  773. subst   endp
  774.  
  775. ; Read chars from Take file, keyboard, or redirected stdin. Edit and remove
  776. ; BS & DEL, Tab becomes space, act on Control-C, pass Control-U and Control-W.
  777. ; Do echoing unless comand.cmquiet is non-zero. Do semicolon comments in Take
  778. ; and indirect stdin files (\; means literal semicolon). Return char in AL.
  779. CMGETC  proc    near                    ; Basic raw character reader
  780.         mov     ah,taklev               ; get current Take level
  781.         mov     intake,ah               ; remember here for later callers
  782. cmget01:cmp     prevch,0                ; left over char yet to be exported?
  783.         je      cmget02                 ; e = no
  784.         mov     al,prevch               ; get old char
  785.         mov     prevch,0                ; clear storage
  786.         jmp     cmget6                  ; analyze it
  787. cmget02:cmp     taklev,0                ; in a Take file?
  788.         jne     cmget1                  ; ne = yes, do Take reader section
  789.         call    isdev                   ; is stdin a device or a file?
  790.         jnc     cmget20                 ; nc = file (redirection of stdin)
  791.         jmp     cmget10                 ; c = device, do separately
  792.  
  793. cmget20:call    iseof                   ; see if file is empty
  794.         jc      cmget21                 ; c = EOF on disk file
  795.         mov     ah,coninq               ; read the char from file, not device
  796.         int     dos
  797.         cmp     al,cr                   ; is it a cr?
  798.         je      cmget01                 ; yes, ignore and read next char
  799.         cmp     al,ctlz                 ; Control-Z?
  800.         je      cmget21                 ; e = yes, same as EOF here
  801.         cmp     al,lf                   ; LF's end lines from disk files
  802.         jne     cmget23                 ; ne = not LF, pass along as is
  803.         mov     al,cr                   ; make LF a CR for this parser
  804.         call    iseof                   ; see if this is the last char in file
  805.         jnc     cmget23                 ; nc = not EOF, process new CR
  806. cmget21:mov     flags.extflg,1          ; EOF on disk file, set exit flag
  807. cmget23:jmp     short cmget6            ; do echoing and return
  808.  
  809. cmget1: push    bx                      ; read from Take file
  810.         mov     bx,takadr
  811.         cmp     [bx].takcnt,0           ; bytes remaining in Take buffer
  812.         jne     cmget4                  ; ne = not empty
  813.         cmp     [bx].taktyp,0feh        ; type of Take (file?)
  814.         jne     cmget3                  ; ne = no (macro)
  815.         call    takrd                   ; read another buffer
  816.         cmp     [bx].takcnt,0           ; anything in the file?
  817.         jne     cmget4                  ; ne = yes
  818. cmget3: pop     bx                      ; clear stack
  819.         jmp     cmget5                  ; close take file
  820.  
  821. cmget4: push    si
  822.         mov     si,[bx].takptr          ; read a char from Take buffer
  823.         cld
  824.         lodsb
  825.         mov     [bx].takptr,si          ; move buffer pointer
  826.         pop     si
  827.         dec     [bx].takcnt             ; decrease number of bytes remaining
  828.         pop     bx
  829.         cmp     al,ctlz                 ; Control-Z?
  830.         jne     cmget6                  ; ne = no
  831. cmget5: cmp     comand.cmkeep,0         ; keep Take/macro open after eof?
  832.         jne     cmget5a                 ; ne = yes
  833.         call    takclos                 ; close take file
  834. cmget5a:mov     al,cr                   ; report cr as last char
  835.         mov     noparse,0               ; and say end of comment
  836.                                         ; start common code
  837. cmget6: cmp     al,lf                   ; line feed?
  838.         jne     cmget8                  ; ne = no
  839.         jmp     cmget01                 ; yes, ignore and read another char
  840.                                         ; handle comments (echo but not parse)
  841. cmget8: cmp     noparse,0               ; parsing?
  842.         jne     cmget9                  ; ne = yes, do echo and no parse
  843.         cmp     prevch,0                ; have previous char to analyze?
  844.         jne     cmget8c                 ; ne = yes
  845.         cmp     al,'\'                  ; start of '\;'?
  846.         jne     cmget8a                 ; ne = no
  847.         mov     prevch,al               ; yes, maybe. save '\' til later
  848.         jmp     cmget02                 ; read next char
  849. cmget8a:cmp     al,';'                  ; possible start of comment?
  850.         jne     cmget8e                 ; no, export al
  851.         mov     al,' '                  ; replace ';' with space for comment
  852.         jmp     cmget9                  ; go start a comment
  853.  
  854. cmget8c:cmp     al,';'                  ; end of '\;'?
  855.         je      cmget8d                 ; e = yes, omit leading backslash
  856.         xchg    prevch,al               ; no, save new, recover old '\'
  857.         jmp     short cmget8e           ; export '\'
  858. cmget8d:mov     prevch,0                ; clear old '\'
  859. cmget8e:jmp     cmget12                 ; do parsing
  860.         mov     prevch,0                ; clear previous char
  861.         jmp     cmget02                 ; get next char
  862.  
  863.                                         ; echo comment
  864. cmget9: cmp     flags.takflg,0          ; echoing take files?
  865.         je      cmget9a                 ; e = no
  866.         push    ax
  867.         push    dx
  868.         mov     ah,conout               ; echo current char
  869.         mov     dl,al
  870.         int     dos
  871.         pop     dx
  872.         pop     ax
  873. cmget9a:mov     noparse,0               ; cr ends comment
  874.         cmp     al,cr                   ; end of comment?
  875.         je      cmget13                 ; e = yes, export cr
  876.         mov     noparse,1               ; still in comment
  877.         jmp     cmget01                 ; read more chars
  878.  
  879.                                         ; read from tty device
  880. cmget10:mov     ah,coninq               ; Get a char from device, not file
  881.         int     dos                     ;  with no echoing
  882.         or      al,al
  883.         jnz     cmget12                 ; ignore null bytes of special keys
  884.         int     dos                     ; read and discard scan code byte
  885.         jmp     cmget10                 ; try again
  886.  
  887. cmget12:cmp     al,'C'and 1Fh           ; Control-C?
  888.         je      cmget14                 ; e = yes
  889.         cmp     al,TAB                  ; tab is replaced by space
  890.         jne     cmget13                 ; ne = not tab
  891.         mov     al,' '
  892. cmget13:ret                             ; normal exit, char is in AL
  893.  
  894. cmget14:mov     ah,prstr                ; Control-C handler
  895.         push    dx
  896.         mov     dx,offset ctcmsg        ; show Control-C
  897.         int     dos
  898.         pop     dx
  899.         mov     prevch,0
  900.         mov     flags.cxzflg,'C'        ; tell others the news
  901.         mov     sp,cmdstk               ; restore command entry stack pointer
  902.         ret                             ;  and fail immediately (a longjmp)
  903. cmgetc  endp
  904.  
  905. ; Read chars from user (cmgetc). Detect terminators. Reads from buffer
  906. ; comand.cmbuf. Set read pointer comand.cmrptr to next free buffer byte if
  907. ; char is not a terminator: chars CR, LF, FF, '?' (returns carry set for
  908. ; terminators). Do ^U, ^W editing, convert FF to CR plus clear screen.
  909. ; Edit "-<cr>" as line continuation, "\-<cr>" as "-<end of line>".
  910. ; Return char in AH.
  911. CMINBF  proc    near                    ; Buffer reader, final editor
  912.         push    di
  913.         mov     di,comand.cmwptr
  914.         cmp     di,offset comand.cmdbuf+size cmdbuf-3 ; max buffer size - 3
  915.         pop     di
  916.         jb      cminb1                  ; b = not full
  917.         mov     ah,conout               ; almost full, notify user
  918.         push    dx
  919.         mov     dl,bell
  920.         int     dos
  921.         mov     dx,offset comand.cmdbuf+size cmdbuf
  922.         cmp     comand.cmrptr,dx        ; max buffer size?
  923.         pop     dx
  924.         jb      cminb1                  ; b = more room
  925.         mov     ah,prstr
  926.         push    dx
  927.         mov     dx,offset cmer09        ; command too long
  928.         int     dos
  929.         pop     dx
  930.         jmp     prserr                  ; overflow = parse error
  931.  
  932. cminb1: push    bx
  933.         mov     bx,comand.cmrptr
  934.         mov     ah,[bx]                 ; get current command char while here
  935.         cmp     bx,comand.cmwptr        ; do we need to read more?
  936.         pop     bx                      ; no if cmrptr < cmwptr
  937.         jb      cminb2                  ; b: cmrptr < cmwptr (have extra here)
  938.         call    cmgetc                  ; no readahead, read another into al
  939.         mov     ah,al                   ; keep char in 'ah'
  940.         push    bx
  941.         mov     bx,comand.cmwptr        ; Get the pointer into the buffer
  942.         mov     [bx],ah                 ; Put it in the buffer
  943.         inc     bx
  944.         mov     comand.cmwptr,bx        ; inc write pointer
  945.         pop     bx
  946.                                         ; Char to be delivered is in ah
  947. cminb2: cmp     ah,'W' and 1fh          ; Is it a ^W?
  948.         jne     cminb3
  949.         call    cntrlw                  ; Kill the previous word
  950.         jnc     cminbf                  ; nc = no change, get another char
  951.         jmp     repars                  ; need a new command scan (cleans stk)
  952.  
  953. cminb3: cmp     ah,'U' and 1fh          ; Is it a ^U?
  954.         jne     cminb3a                 ; ne = no
  955.         mov     comand.cmwptr,offset comand.cmdbuf ;reset buffer write pointer
  956.         jmp     repars                  ; Go start over (cleans stack)
  957.                                         ; BS and DEL
  958. cminb3a:cmp     ah,DEL                  ; Delete code?
  959.         je      cminb3b                 ; e = yes
  960.         cmp     ah,BS                   ; Backspace (a delete operator)?
  961.         jne     cminb4                  ; ne = no
  962. cminb3b:call    bufdel                  ; delete char from buffer
  963.         jc      cminb3c                 ; c = did erasure
  964.         jmp     cminbf                  ; no erasure, ignore BS, get more
  965. cminb3c:jmp     repars                  ; could have deleted previous token
  966.  
  967. cminb4: push    bx                      ; look for hyphen or \hyphen
  968.         cmp     ah,cr                   ; check for hyphen line continuation
  969.         jne     cminb4b                 ; ne = not end of line
  970.         mov     bx,comand.cmwptr        ; Get the pointer into the buffer
  971.         cmp     bx,offset comand.cmdbuf-2 ; do we have a previous char?
  972.         jb      cminb4b                 ; b = no
  973.         cmp     byte ptr[bx-2],'-'      ; previous char was a hyphen?
  974.         jne     cminb4b                 ; ne = no
  975.         pop     bx
  976.         call    bufdel                  ; delete the hyphen
  977.         jmp     repars
  978. cminb4b:pop     bx
  979.                                         ; Echoing done here
  980.         cmp     comand.cmquiet,0        ; quiet mode?
  981.         jne     cminb5                  ; yes, skip echoing
  982.         cmp     taklev,0                ; in a take file?
  983.         je      cminb4a                 ; e = no
  984.         cmp     flags.takflg,0          ; echo take file?
  985.         je      cminb5                  ; e = no
  986. cminb4a:push    ax                      ; save the char
  987.         cmp     ah,' '                  ; printable?
  988.         jae     cminb4c                 ; yes, no translation needed
  989.         cmp     ah,cr                   ; this is printable
  990.         je      cminb4c
  991.         cmp     ah,lf
  992.         je      cminb4c
  993.         cmp     ah,escape               ; escape?
  994.         je      cminb4d                 ; do not echo this character
  995.         push    ax                      ; show controls as caret char
  996.         push    dx
  997.         mov     dl,5eh                  ; caret
  998.         mov     ah,conout
  999.         int     dos
  1000.         pop     dx
  1001.         pop     ax
  1002.         add     ah,'A'-1                ; make control code printable
  1003. cminb4c:push    dx
  1004.         mov     dl,ah
  1005.         mov     ah,conout
  1006.         int     dos                     ; echo it ourselves
  1007.         pop     dx
  1008. cminb4d:pop     ax                      ; and return char in ah
  1009.  
  1010. cminb5: cmp     ah,cr                   ; Is it a carriage return?
  1011.         je      cminb6
  1012.         cmp     ah,lf                   ; Is it a line feed?
  1013.         je      cminb6
  1014.         cmp     ah,ff                   ; Is it a formfeed?
  1015.         jne     cminb7                  ; none of the above, report bare char
  1016.         call    cmblnk                  ; FF: clear the screen and
  1017.         push    bx
  1018.         push    cx
  1019.         push    dx
  1020.         call    locate                  ; Home the cursor
  1021.         mov     bx,comand.cmwptr        ; make the FF parse like a cr
  1022.         mov     byte ptr [bx-1],cr      ; pretend a carriage return were typed
  1023.         pop     dx
  1024.         pop     cx
  1025.         pop     bx
  1026. cminb6: cmp     comand.cmwptr,offset comand.cmdbuf ; parsed any chars yet?
  1027.         jne     cminb7                  ; ne = yes
  1028.         cmp     comand.cmcr,0           ; bare cr's allowed?
  1029.         jne     cminb7                  ; ne = yes
  1030.         jmp     prserr                  ; If not, just start over
  1031. cminb7: clc
  1032.         ret
  1033. cminbf  endp
  1034.  
  1035. ; Read chars from cminbf. Comand.cmrptr points to next char to be read.
  1036. ; Compresses repeated spaces if comand.cmsflg is non-zero. Exit with
  1037. ; comand.cmrptr pointing at a terminator or otherwise at next free slot.
  1038. ; Non-space then space acts as a terminator but comand.cmrptr is incremented.
  1039. ; Substitution variables, '\%x', are detected and expanded. Return char in AH.
  1040.  
  1041. CMGTCH  proc    near                    ; return char in AH, from rescan buf
  1042.         call    cminbf                  ; get char from buffer or user
  1043.         push    bx
  1044.         mov     bx,comand.cmrptr        ; get read pointer into the buffer
  1045.         mov     ah,[bx]                 ; read the next char
  1046.         inc     bx
  1047.         mov     comand.cmrptr,bx        ; where to read next time
  1048.         pop     bx
  1049.         call    subst                   ; examine for text substitution
  1050.         jnc     cmgtc1                  ; nc = no substitutions done
  1051.         jmp     repars                  ; reparse line with new material
  1052.  
  1053. cmgtc1: cmp     ah,' '                  ; Is it a space?
  1054.         jne     cmgtc3                  ; ne = no
  1055. cmgtc2: cmp     comand.cmsflg,0         ; space flag, was last char a space?
  1056.         jne     cmgtch                  ; ne = yes, get another char
  1057.         mov     comand.cmsflg,0FFH      ; Set the space(s)-seen flag
  1058.         mov     ah,' '                  ; character for caller
  1059.         stc                             ; set carry for terminator
  1060.         ret                             ; return space as a terminator
  1061. cmgtc3: mov     comand.cmsflg,0         ; clear the space-seen flag
  1062.         cmp     ah,escape               ; terminators remain in buffer but
  1063.         je      cmgtc4                  ;  are ready to be overwritten
  1064.         cmp     ah,'?'                  ; Is the user curious?
  1065.         jne     cmgtc3a                 ; ne = no
  1066.         cmp     taklev,0                ; in a Take file?
  1067.         jne     cmgtc3b                 ; ne = yes, make query ordinary char
  1068.         je      cmgtc4
  1069. cmgtc3a:cmp     ah,cr
  1070.         je      cmgtc4
  1071.         cmp     ah,lf
  1072.         je      cmgtc4
  1073.         cmp     ah,ff
  1074.         je      cmgtc4
  1075. cmgtc3b:clc                             ; carry clear for non-terminator
  1076.         ret
  1077. cmgtc4: dec     comand.cmrptr           ; point at terminating char
  1078.         stc                             ; set carry to say it is a terminator
  1079.         ret
  1080. cmgtch  endp
  1081.  
  1082. ; Reset comand.cmdbuf write pointer (.cmwptr) to where the read pointer
  1083. ; (.cmrptr) is now. Discards material not yet read.
  1084. bufreset proc   near
  1085.         push    comand.cmrptr           ; where next visible char is read
  1086.         pop     comand.cmwptr           ; where new char goes in buffer
  1087.         ret
  1088. bufreset endp
  1089.  
  1090. ; Delete character from screen and adjust buffer. Returns carry clear if
  1091. ; no erasure, carry set otherwise.
  1092. bufdel  proc    near
  1093.         dec     comand.cmrptr           ; remove previous char from buffer
  1094.         cmp     comand.cmrptr,offset comand.cmdbuf ; back too far?
  1095.         jae     bufde2                  ; ae = no, material can be erased
  1096.         mov     comand.cmrptr,offset comand.cmdbuf ; set to start of buffer
  1097.         call    bufreset                ; reset buffer
  1098.         clc                             ; say no erasure
  1099.         ret
  1100. bufde2: call    bufreset                ; reset buffer
  1101.         stc                             ; say did erasure
  1102.         ret
  1103. bufdel  endp
  1104.  
  1105. ; Come here is user types ^W when during input. Remove word from buffer.
  1106. cntrlw  proc    near
  1107.         push    ax
  1108.         push    cx
  1109.         push    dx
  1110.         mov     cx,comand.cmrptr        ; char beyond what user sees
  1111.         mov     comand.cmwptr,cx        ; truncate buffer there
  1112.         sub     cx,offset comand.cmdbuf ; compute chars in buffer
  1113.         clc                             ; say have not yet modified line
  1114.         jcxz    ctlw2                   ; z = nothing to do, exit no-carry
  1115.         push    es
  1116.         std                             ; scan backward
  1117.         mov     ax,ds
  1118.         mov     es,ax                   ; point to the data are
  1119.         mov     di,comand.cmwptr        ; looking from here
  1120.         dec     di
  1121.         mov     al,' '
  1122.         repe    scasb                   ; look for non-space
  1123.         je      ctlw1                   ; all spaces, nothing to do
  1124.         inc     di                      ; move back to non-space
  1125.         inc     cx
  1126.         repne   scasb                   ; look for a space
  1127.         jne     ctlw1                   ; no space, leave ptrs alone
  1128.         inc     di
  1129.         inc     cx                      ; skip back over space
  1130. ctlw1:  inc     di
  1131.         pop     es
  1132.         cld                             ; reset direction flag
  1133.         mov     comand.cmwptr,di        ; update pointer
  1134.         stc                             ; set carry to say modified line
  1135. ctlw2:  pop     dx
  1136.         pop     cx
  1137.         pop     ax
  1138.         ret
  1139. cntrlw  endp
  1140.  
  1141. ; Jump to REPARS to do a rescan of the existing buffer.
  1142. ; Jump to PRSERR on a parsing error (quits command, clears old read material)
  1143.  
  1144. PRSERR  PROC NEAR
  1145.         mov     comand.cmwptr,offset comand.cmdbuf ; initialize write pointer
  1146.         mov     ah,prstr
  1147.         mov     dx,offset crlf          ; leave old line, start a new one
  1148.         int     dos
  1149.                                         ; reparse current line
  1150. REPARS: mov     comand.cmrptr,offset comand.cmdbuf ; reinit read pointer
  1151.         mov     comand.cmper,0          ; reset to variable recognition
  1152.         mov     comand.cmsflg,0FFH      ; strip leading spaces
  1153.         cmp     taklev,0                ; in Take cmd?
  1154.         je      prser2                  ; e = no
  1155.         cmp     flags.takflg,0          ; echo contents of Take file?
  1156.         je      prser3                  ; e = no
  1157. prser2: call    ctlu                    ; clear display's line, reuse it
  1158.         mov     ah,prstr
  1159.         mov     dx,comand.cmprmp        ; display the prompt
  1160.         int     dos
  1161. prser3: mov     bx,0ffffh               ; returned keyword value
  1162.         mov     sp,comand.cmostp        ; set new sp to old one
  1163.         jmp     comand.cmrprs           ; jump to just before the prompt call
  1164. PRSERR  ENDP
  1165.  
  1166. ; This routine prints the prompt and specifies the reparse address.
  1167. ; Enter with pointer to prompt string in dx.
  1168. PROMPT  PROC  NEAR
  1169.         mov     comand.cmprmp,dx        ; save the prompt
  1170.         pop     ax                      ; Get the return address
  1171.         mov     comand.cmrprs,ax        ; Save as address to go to on reparse
  1172.         mov     comand.cmostp,sp        ; Save for later restoration
  1173.         push    ax                      ; Put it on the stack again
  1174.         mov     ax,offset comand.cmdbuf
  1175.         mov     comand.cmwptr,ax        ; reset buffer read/write pointers
  1176.         mov     comand.cmrptr,ax
  1177.         mov     ax,0
  1178.         mov     comand.cmper,0          ; allow substitutions
  1179.         mov     comand.cmsflg,0FFH      ; remove leading spaces
  1180.         cmp     flags.takflg,0          ; look at Take flag
  1181.         jne     promp1                  ; ne=supposed to echo, skip this check
  1182.         cmp     taklev,0                ; inside a take file?
  1183.         je      promp1                  ; no, keep going
  1184.         ret                             ; yes, return
  1185. promp1: mov     ah,prstr
  1186.         mov     dx,offset crlf
  1187.         int     dos
  1188.         mov     ah,prstr                ; display the prompt
  1189.         mov     dx,comand.cmprmp
  1190.         int     dos
  1191.         ret
  1192. PROMPT  ENDP
  1193.  
  1194. ISDEV   PROC    NEAR                    ; Set carry if STDIN is non-disk
  1195.         push    ax
  1196.         push    bx
  1197.         push    dx
  1198.         mov     al,0                    ; get device info
  1199.         mov     ah,ioctl
  1200.         mov     bx,0                    ; handle 0 is stdin
  1201.         int     dos
  1202.         and     dl,80h                  ; bit set if handle is for a device
  1203.         rcl     dl,1                    ; put it into the carry bit
  1204.         pop     dx
  1205.         pop     bx
  1206.         pop     ax
  1207.         ret                             ; carry set if device
  1208. ISDEV   ENDP
  1209.  
  1210. ISEOF   PROC    NEAR                    ; Set carry if STDIN is at EOF
  1211.         push    ax                      ;  but only if stdin is a non-device
  1212.         push    bx
  1213.         push    dx
  1214.         mov     al,0                    ; get device info
  1215.         mov     ah,ioctl
  1216.         mov     bx,0                    ; handle 0 is stdin
  1217.         int     dos
  1218.         test    dl,80h                  ; bit set if handle is for a device
  1219.         mov     ah,ioctl
  1220.         mov     al,6                    ; get handle input status, set al
  1221.         jnz     iseof1                  ; nz = device, always ready (al != 0)
  1222.         int     dos
  1223. iseof1: or      al,al                   ; EOF?
  1224.         pop     dx
  1225.         pop     bx
  1226.         pop     ax
  1227.         jnz     iseof2                  ; nz = no
  1228.         stc                             ; set carry for eof
  1229.         ret
  1230. iseof2: clc                             ; clear carry for not-eof
  1231.         ret
  1232. ISEOF   ENDP
  1233. ; Convert ascii characters in al and ah to lowercase. [jrd]
  1234. ; All registers are preserved except AX, of course.
  1235.  
  1236. TOLOWR PROC NEAR
  1237.         cmp     ah,'A'                  ; less that cap A?
  1238.         jl      tolow1                  ; l = yes. leave untouched
  1239.         cmp     ah,'Z'+1                ; more than cap Z?
  1240.         jns     tolow1                  ; ns = yes
  1241.         or      ah,20H                  ; convert to lowercase
  1242. tolow1: cmp     al,'A'                  ; less that cap A?
  1243.         jl      tolow2                  ; l = yes. leave untouched
  1244.         cmp     al,'Z'+1                ; more than cap Z?
  1245.         jns     tolow2                  ; ns = yes
  1246.         or      al,20H                  ; convert to lowercase
  1247. tolow2: ret
  1248. TOLOWR  endp
  1249.  
  1250. ; Jumping to this location is like retskp.  It assumes the instruction
  1251. ;   after the call is a jmp addr.
  1252.  
  1253. RSKP    PROC    NEAR
  1254.         pop     bp
  1255.         add     bp,3
  1256.         push    bp
  1257.         ret
  1258. RSKP    ENDP
  1259.  
  1260. ; Jumping here is the same as a ret.
  1261.  
  1262. R       PROC    NEAR
  1263.         ret
  1264. R       ENDP
  1265.  
  1266. code    ends
  1267.         end
  1268.